package cn.com.bluemoon.daps.standard.controller;


import cn.com.bluemoon.daps.common.datascope.BmPermission;
import cn.com.bluemoon.daps.common.domain.ResultBean;
import cn.com.bluemoon.daps.common.enums.BmStatus;
import cn.com.bluemoon.daps.common.enums.StandardAuditStatus;
import cn.com.bluemoon.daps.common.mp.IBmService;
import cn.com.bluemoon.daps.common.webhook.Authors;
import cn.com.bluemoon.daps.standard.common.IndexStandardVersionResponse;
import cn.com.bluemoon.daps.standard.dto.StandardQueryDto;
import cn.com.bluemoon.daps.standard.entity.DapStandardAuditVersionMain;
import cn.com.bluemoon.daps.standard.entity.DapStandardIndex;
import cn.com.bluemoon.daps.standard.entity.DapStandardVersion;
import cn.com.bluemoon.daps.standard.excel.pojo.IndexStandardExport;
import cn.com.bluemoon.daps.standard.service.DapStandardIndexService;
import cn.com.bluemoon.daps.standard.service.DapStandardModifyService;
import cn.com.bluemoon.daps.standard.service.DapStandardVersionService;
import cn.com.bluemoon.daps.standard.vo.BasicStandardFormVo;
import cn.com.bluemoon.daps.standard.vo.IndexStandardRelateDwModelVo;
import cn.com.bluemoon.daps.standard.vo.IndexStandardVo;
import cn.com.bluemoon.daps.standard.vo.MetaDataTableInfoVO;
import cn.com.bluemoon.metadata.inter.RemoteModelMetaDataTableService;
import cn.com.bluemoon.metadata.inter.dto.in.QueryMetaDataTableInfoRequest;
import cn.com.bluemoon.metadata.inter.dto.out.ModelMetaDataTableInfoVO;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 * 指标标准表 前端控制器
 * </p>
 *
 * @author admin
 * @since 2020-08-03
 */
@Api(tags = "指标标准")
@RestController
@Slf4j
@Authors(value = @Authors.Author(name = "Jarod.Kong", desc = "指标标准查询", devTime = ""))
@RequestMapping("/dapStandardIndex")
public class DapStandardIndexController {

    private static final String SYS_CATEGORY_QUERY_ALL_ID = "#all";

    @Autowired
    private DapStandardIndexService standardIndexService;

    @Autowired
    private RemoteModelMetaDataTableService remoteModelMetaDataTableService;

    @Resource
    private DapStandardModifyService dapStandardModifyService;

    @Autowired
    private DapStandardVersionService versionService;

    @BmPermission(value = "standard:query:index:query", name = "指标标准列表查询")
    @PostMapping("/list")
    @ApiOperation(value = "根据主题id和层级分类获取分类列表数据-用于分类列表中")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = IndexStandardVo.class)})
    public ResultBean<?> categories(@RequestBody @Valid BasicStandardFormVo<DapStandardIndex> queryDto) {
        LambdaQueryWrapper<DapStandardIndex> where = getDapStandardIndexLambdaQueryWrapper(queryDto);

        Page<DapStandardIndex> standardIndexPage = queryDto.toMpPage();
        IPage<DapStandardIndex> page = standardIndexService.page(standardIndexPage, where);
        page.convert(d -> {
            IndexStandardVo indexStandardVo = new IndexStandardVo(d);
            standardIndexService.transferDicInfo(d, indexStandardVo);
            // 增加flag 标识该标准在流程变更中存在待发布数据，是为true，否false
            boolean auditChanging = dapStandardModifyService.analyseAuditChanging(indexStandardVo);
            indexStandardVo.setAuditChanging(auditChanging);
            return indexStandardVo;
        });
        return IBmService.toAntDvPageTool(page);
    }

    private LambdaQueryWrapper<DapStandardIndex> getDapStandardIndexLambdaQueryWrapper(BasicStandardFormVo<DapStandardIndex> queryDto) {
        LambdaQueryWrapper<DapStandardIndex> where = Wrappers.lambdaQuery(new DapStandardIndex())
                .orderByAsc(DapStandardIndex::getIndexChinName)
                .eq(DapStandardIndex::getPublishNewest, Boolean.TRUE)
                .eq(StringUtils.isNotBlank(queryDto.getTopicId()), DapStandardIndex::getTheme, queryDto.getTopicId())
                .eq(DapStandardIndex::getBmStatus, BmStatus.ON)
                .eq(StringUtils.isNotBlank(queryDto.getCategory1()) &&
                                !SYS_CATEGORY_QUERY_ALL_ID.equalsIgnoreCase(queryDto.getCategory1()),
                        DapStandardIndex::getPrimarySort, queryDto.getCategory1())
                .eq(StringUtils.isNotBlank(queryDto.getCategory2()) &&
                                !SYS_CATEGORY_QUERY_ALL_ID.equalsIgnoreCase(queryDto.getCategory2()),
                        DapStandardIndex::getSecondarySort, queryDto.getCategory2())
                .eq(StringUtils.isNotBlank(queryDto.getCategory3()) &&
                                !SYS_CATEGORY_QUERY_ALL_ID.equalsIgnoreCase(queryDto.getCategory3()),
                        DapStandardIndex::getThirdSort, queryDto.getCategory3())
                .eq(StringUtils.isNotBlank(queryDto.getDepartmentId()) &&
                                !SYS_CATEGORY_QUERY_ALL_ID.equalsIgnoreCase(queryDto.getDepartmentId()),
                        DapStandardIndex::getManagementDepartmentId, queryDto.getDepartmentId())
                // 增加指标类型 业务线
                .eq(queryDto.getIndexType() != -1 && queryDto.getIndexType() != null,
                        DapStandardIndex::getIndexType, queryDto.getIndexType())
                .eq(queryDto.getBizLineId() != -1 && queryDto.getBizLineId() != null,
                        DapStandardIndex::getBizLineId, queryDto.getBizLineId())
                .and(StringUtils.isNotBlank(queryDto.getKeyword()), wrapper ->
                        wrapper.like(DapStandardIndex::getIndexChinName, queryDto.getKeyword())
                                .or()
                                .like(DapStandardIndex::getIndexEngName, queryDto.getKeyword())
                                .or()
                                .like(DapStandardIndex::getBusinessDefinition, queryDto.getKeyword()));
        return where;
    }

    /**
     * @param id 标准id
     * @return {@link ResultBean}
     * @since 2020年10月12日19:43:13 删除功能调整（期初理解为直接进行对标准删除，而今天落地确认为
     * <em>删除标准的业务逻辑是：启动一个删除的流程审批数据
     * （即变更类型为{@link DapStandardAuditVersionMain#getModifyType()} == 3以及变更状态为{@link StandardAuditStatus#草稿}的流程数据）</em>
     * 而最终是否删除标准，取决于是否通过待审批，若待审批通过则对{@link DapStandardAuditVersionMain#getModifyType()} == 3进行删除整个标准的流程数据和引用关系
     * 注意：其中{@link DapStandardAuditVersionMain#getModifyType()} == 3的流程数据是不可编辑的、
     * 并且要确保{@link DapStandardAuditVersionMain#getModifyType()} 一直为3（删除）来确保通过审批进行删除
     */
    @BmPermission(value = "standard:query:index:delete", name = "指标标准删除")
    @ApiResponses({@ApiResponse(code = 200, message = "ok", response = ResultBean.class)})
    @DeleteMapping({"/{id}"})
    @ApiOperation("确定删除数据，及其相应联级数据")
    public ResultBean<?> deleteAudit(@PathVariable String id) {
        dapStandardModifyService.deleteAudit(id, 1);
//        standardIndexService.deleteStandardIndex(id, true);
        return ResultBean.ok();
    }

    @BmPermission(value = "standard:query:index:view", name = "指标标准查看")
    @GetMapping("/{id}")
    @ApiOperation(value = "根据标准id获取标准数据和报表信息")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = ResultBean.class)})
    public ResultBean<IndexStandardVo> indexGet(@PathVariable String id) {
        DapStandardIndex standardIndex = standardIndexService.getByIdAsset(id);
        IndexStandardVo indexStandardVo = new IndexStandardVo(standardIndex);
        String dataWarehouseModel = standardIndex.getDataWarehouseModel();
        if (dataWarehouseModel != null && dataWarehouseModel.contains(".")) {
            List<QueryMetaDataTableInfoRequest> requests = new ArrayList<>();
            QueryMetaDataTableInfoRequest request = new QueryMetaDataTableInfoRequest();
            String[] tableAndColumn = dataWarehouseModel.split("\\.");
            request.setTableName(tableAndColumn[0]);
            request.setColumnName(tableAndColumn[1]);
            requests.add(request);
            cn.com.bluemoon.metadata.common.ResultBean<List<ModelMetaDataTableInfoVO>> res = remoteModelMetaDataTableService.queryMetaDataTableInfoByTableColumn(requests);
            if (res.isSuccess() && !res.getContent().isEmpty()){
                List<ModelMetaDataTableInfoVO> modelMetaDataTableInfoVOS = res.getContent();
                ModelMetaDataTableInfoVO tableInfoVO = modelMetaDataTableInfoVOS.get(0);
                indexStandardVo.setDataWarehouseModelTableMoiDataId(tableInfoVO.getTableMoiDataId());
                indexStandardVo.setDataWarehouseModelTableGuid(tableInfoVO.getTableGuid());
                indexStandardVo.setDataWarehouseModelColumnGuid(tableInfoVO.getColumnGuid());
                MetaDataTableInfoVO metaDataTableInfoVO = new MetaDataTableInfoVO();
                BeanUtils.copyProperties(tableInfoVO, metaDataTableInfoVO);
                indexStandardVo.setMetaDataTableInfoVO(metaDataTableInfoVO);
            }
        }

        List<IndexStandardVo.ReportInfo> reportInfos = standardIndexService.relateReportInfo(id);
        indexStandardVo.setReportInfos(reportInfos);
        standardIndexService.transferDicInfo(standardIndex, indexStandardVo);
        // 增加flag 标识该标准在流程变更中存在待发布数据，是为true，否false
        boolean auditChanging = dapStandardModifyService.analyseAuditChanging(indexStandardVo);
        indexStandardVo.setAuditChanging(auditChanging);
        LambdaQueryWrapper<DapStandardVersion> eq = versionService.bmLambdaQuery().eq(DapStandardVersion::getStandardUniqueId, standardIndex.getStandardUniqueId())
                .orderByAsc(DapStandardVersion::getId).orderByAsc(DapStandardVersion::getModifyTime);
        List<DapStandardVersion> versions = versionService.list(eq);
        AtomicInteger version = new AtomicInteger(1);
        List<IndexStandardVersionResponse> versionResponses = versions.stream().map(v -> new IndexStandardVersionResponse(v, true))
                .peek(v -> v.setVersion(String.format("V%d", version.getAndIncrement()))).collect(Collectors.toList());
        return ResultBean.ok(indexStandardVo)
                .addMoreData("versions", versionResponses);
    }

    @BmPermission(value = "standard:query:index:view", name = "指标标准查看(已发布的指标标准列表数据）历史版本")
    @GetMapping("/version")
    @ApiOperation(value = "获取已发布的标准数据的历史版本")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = ResultBean.class)})
    public ResultBean<IndexStandardVersionResponse> versionView(@RequestParam(value = "versionId") String versionId) {
        DapStandardVersion standardVersion = versionService.getById(versionId);
        IndexStandardVersionResponse versionResponse = Optional.ofNullable(standardVersion).filter(d -> BmStatus.ON.equals(d.getBmStatus())).map(IndexStandardVersionResponse::new).orElse(null);
        return ResultBean.ok(versionResponse);
    }

    @BmPermission(value = "standard:query:index:view", name = "指标标准查看(已发布的指标标准列表数据）")
    @GetMapping("/publishIndex")
    @ApiOperation(value = "获取已发布的标准数据")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = ResultBean.class)})
    public ResultBean<List<IndexStandardVo>> publishIndex(@RequestParam(value = "standardId", required = false) String standardId) {
        String standardUniqueId = null;
        //noinspection AliControlFlowStatementWithoutBraces
        DapStandardIndex standard;
        if (standardId != null && (standard = standardIndexService.getById(standardId)) != null) {
            standardUniqueId = standard.getStandardUniqueId();
        }
        Collection<DapStandardIndex> publishStandardIndexes = standardIndexService.getPublishStandardIndexes(standardUniqueId);
        List<IndexStandardVo> collect = publishStandardIndexes.stream().filter(Objects::nonNull).map(d -> {
            IndexStandardVo indexStandardVo = new IndexStandardVo(d);
            // 目前已发布接口不需要对主题分类和系统信息去掉，影响性能
            /*standardIndexService.transferDicInfo(d, indexStandardVo);*/
            return indexStandardVo;
        }).collect(Collectors.toList());
        return ResultBean.ok(collect);
    }

    @PostMapping("/relate/model")
    @ApiOperation(value = "根据主题id和层级分类获取分类列表数据-用于分类列表中")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = IndexStandardVo.class)})
    @BmPermission(value = {"standard:modify:index:edit"}, name = "标准变更-指标标准编辑")
    public ResultBean<String> relateDwTableInfo(@RequestBody @Valid IndexStandardRelateDwModelVo relateDwModelVo) {
        String relateId = standardIndexService.relateDwModelTableInfo(relateDwModelVo);
        return ResultBean.ok(relateId);
    }

    @GetMapping("/exportByCondition")
    @ApiOperation(value = "导出已发布后的指标标准数据")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = Void.class)})
    @BmPermission(value = {"standard:modify:index:edit"}, name = "标准变更-导出已发布后的指标标准数据", queryTokenPerm = true)
    public void exportByCondition(HttpServletResponse response,
                                  @RequestParam(required = true) String topicId,
                                  @RequestParam(required = false) String category1,
                                  @RequestParam(required = false) String category2,
                                  @RequestParam(required = false) String category3,
                                  @RequestParam(required = false) String keyword,
                                  @RequestParam(required = false) String departmentId,
                                  @RequestParam(required = false) Integer indexType,
                                  @RequestParam(required = false) Integer bizLineId) throws IOException {
        String filename = "指标标准导出.xlsx";
        String fileEncode = StandardCharsets.UTF_8.name();
        String outFileName = filename;
        // 告诉浏览器输出内容为流
        response.setHeader("Content-Type", "application/octet-stream;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + outFileName + ";filename*=utf-8''"
                + URLEncoder.encode(outFileName, fileEncode));
        try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("download/" + filename)) {
            StandardQueryDto queryDto = new StandardQueryDto();
            queryDto.setTopicId(topicId);
            queryDto.setCategory1(category1);
            queryDto.setCategory2(category2);
            queryDto.setCategory3(category3);
            queryDto.setKeyword(keyword);
            queryDto.setDepartmentId(departmentId);
            queryDto.setIndexType(indexType);
            queryDto.setBizLineId(bizLineId);
            EasyExcel.write(response.getOutputStream()).withTemplate(inputStream).sheet().doFill(exportData(queryDto));
        }
    }

    @GetMapping("/export")
    @ApiOperation(value = "导出已发布后的指标标准数据（全量）")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = Void.class)})
    @BmPermission(value = {"standard:modify:index:edit"}, name = "标准变更-导出已发布后的指标标准数据（全量）", queryTokenPerm = true)
    public void exportAll(HttpServletResponse response) throws IOException {
        String filename = "指标标准导出.xlsx";
        String fileEncode = StandardCharsets.UTF_8.name();
        String outFileName = filename;
        // 告诉浏览器输出内容为流
        response.setHeader("Content-Type", "application/octet-stream;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + outFileName + ";filename*=utf-8''"
                + URLEncoder.encode(outFileName, fileEncode));
        try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("download/" + filename)) {
            EasyExcel.write(response.getOutputStream()).withTemplate(inputStream).sheet().doFill(exportData(null));
        }
    }

    private List<IndexStandardExport> exportData(StandardQueryDto queryDto) {
        List<IndexStandardExport> data = standardIndexService.exportData(queryDto);
        return data;
    }
}
